extends Node
class_name GenerateMapUtil

var all_rome_map := preload("res://src/map/room/all_room_map.tres")

static var radius: int = 200


func generate_room(array):
	for a1 in array:
		for location: Location in a1:
			if location.level == 0:
				location.res = all_rome_map.map[AllRoomMap.ROOM_TYPE.INIT]
			elif location.level == 1:
				location.res = all_rome_map.map[AllRoomMap.ROOM_TYPE.PRIMARY_MONSTER]
			elif location.level == 6:
				location.res = all_rome_map.map[AllRoomMap.ROOM_TYPE.BOSS_MONSTER]
			else:
				if randf() < 0.2:
					location.res = all_rome_map.map[AllRoomMap.ROOM_TYPE.SHOP]
				else:
					location.res = all_rome_map.map[AllRoomMap.ROOM_TYPE.INTERMEDIATE_MONSTER]


func generate_map(point, array: Array):
	var circle_array = []
	var matrix = generate_neighbor_matrix(array)
	var base_dir = 360 / matrix[1].size()
	for i in range(matrix.size()):
		var last = matrix.size() - 1 == i
		circle_array.append(generate_on_circle(point, i * radius, matrix[i], base_dir, last))
	for m in matrix:
		for m1 in m:
			print(m1.print_self())

	generate_room(circle_array)
	return circle_array


func generate_neighbor_matrix(array: Array):
	var matrix = init_matrix(array)

	for matrix_index in range(2, matrix.size()):
		var temp = generate_neighbor_array(array[matrix_index], array[matrix_index - 1])
		if matrix[matrix_index].size() > matrix[matrix_index - 1].size():
			var matrix_second_index = 0
			for j in range(temp.size()):
				for h in range(temp[j]):
					matrix[matrix_index][matrix_second_index].neighbor.append(
						matrix[matrix_index - 1][j]
					)
					matrix[matrix_index - 1][j].neighbor.append(
						matrix[matrix_index][matrix_second_index]
					)
					matrix[matrix_index][matrix_second_index].tag = matrix[matrix_index - 1][j].tag
					matrix_second_index += 1

		else:
			var matrix_second_index = 0
			for j in range(temp.size()):
				for h in range(temp[j]):
					matrix[matrix_index - 1][matrix_second_index].neighbor.append(
						matrix[matrix_index][j]
					)
					matrix[matrix_index][j].neighbor.append(
						matrix[matrix_index - 1][matrix_second_index]
					)
					#判断是否垮了tag,如果是跨tag的节点,我们希望生成在两个tag中间,防止太偏而导致路线重叠
					if (
						matrix[matrix_index][j].tag
						== matrix[matrix_index - 1][matrix_second_index].tag - 1
					):
						matrix[matrix_index][j].skip_tag = (
							matrix[matrix_index - 1][matrix_second_index].tag - 1
						)
					matrix[matrix_index][j].tag = matrix[matrix_index - 1][matrix_second_index].tag
					matrix_second_index += 1

		var tag = matrix[matrix_index][0].tag
		var sub_index = 0
		for m in range(matrix[matrix_index].size()):
			var location = matrix[matrix_index][m]
			if location.tag == tag:
				location.sub_index = sub_index
				sub_index += 1
				for i in range(sub_index):
					matrix[matrix_index][m - i].sub_array_size = sub_index
				continue
			else:
				for i in range(1, sub_index):
					matrix[matrix_index][m - i].sub_array_size = sub_index
				tag = location.tag
				sub_index = 0
				location.sub_index = sub_index
				location.sub_array_size = 1
				sub_index += 1
	return matrix


func init_matrix(array: Array):
	var matrix = Array()
	matrix.resize(array.size())
	var index = 0
	for k in range(array.size()):
		var a = array[k]
		matrix[k] = Array()
		for j in a:
			var l = Location.new()
			l.index = index
			matrix[k].append(l)
			index += 1

	matrix[0][0].tag = 0
	matrix[0][0].sub_array_size = 1

	for i in range(array[1]):
		matrix[1][i].neighbor.append(matrix[0][0])
		matrix[0][0].neighbor.append(matrix[1][i])
		matrix[1][i].tag = i
		matrix[1][i].sub_array_size = 1
		matrix[1][i].base_location = true
	return matrix


func generate_neighbor_array(a1_size: int, a2_size: int):
	if a1_size > a2_size:
		var temp = a1_size
		a1_size = a2_size
		a2_size = temp

	var quotient = a2_size / a1_size  # 商
	var remainder = a2_size % a1_size  # 余数
	var result = []

	# 平均分配整除部分
	for i in range(a1_size):
		result.append(quotient)
	# 平均分配余数部分

	for i in range(remainder):
		var randomIndex = randi_range(0, a1_size - 1)
		result[randomIndex] = result[randomIndex] + 1
	return result


func generate_on_circle(point: Vector2, r: float, num_points: Array, base_dir: int, last: bool):
	var array: Array[Location] = []
	for o in range(num_points.size()):
		num_points[o].radius = r
		even_circle(point, r, num_points[o], base_dir, last)
		array.append(num_points[o])
	return array


func even_circle(point: Vector2, r: float, l: Location, base_dir: int, last: bool):
	var v = l.tag
	if l.base_location:
		l.location = circle(point, r, base_dir * v)
		return
	var per := base_dir / l.sub_array_size

	var i = l.sub_index
	var skip_tag = l.skip_tag
	if l.skip_tag != -1:
		if skip_tag < v:
			skip_tag = v
		print(
			str(l.index) + " " + str(base_dir * skip_tag - 20) + "-" + str(base_dir * skip_tag + 20)
		)
		l.location = circle(
			point, r, randi_range(base_dir * skip_tag - 20, base_dir * skip_tag + 20)
		)
	else:
		if last:
			var p = (base_dir * v + per * i + base_dir * v + per * (i + 1)) / 2
			print(str(l.index) + " " + str(p))
			l.location = circle(point, r, p)
		else:
			var left = base_dir * v + per * i
			var right = base_dir * v + per * (i + 1)
			var ll = (left + right) / 2 - per * 0.1
			var rr = (left + right) / 2 + per * 0.1
			print(str(l.index) + " " + str(ll) + "-" + str(rr))
			l.location = circle(point, r, randi_range(ll, rr))


func circle(point: Vector2, r: float, i: int):
	var y = 0
	var x = 0
	if i >= 180 and i < 270:
		#y<0
		y = sin(deg_to_rad(i)) * r
		x = sqrt(r * r - y * y) * -1
	elif i >= 270 and i < 360:
		#y<0
		y = sin(deg_to_rad(i)) * r
		x = sqrt(r * r - y * y)
	elif i >= 90 and i < 180:
		#y>0
		y = sin(deg_to_rad(i)) * r
		x = sqrt(r * r - y * y) * -1
	else:
		y = sin(deg_to_rad(i)) * r
		x = sqrt(r * r - y * y)
	return point + Vector2(x, y)


class Location:
	var location: Vector2
	var center: Vector2
	var radius: int:
		set = set_radius
	var neighbor: Array[Location]
	var index: int
	var tag: int = -99
	var sub_index: int
	var sub_array_size: int
	var skip_tag: int = -1
	var base_location: bool = false
	var level: int = 0
	var res: Resource

	func set_radius(ra):
		radius = ra
		self.level = ra / GenerateMapUtil.radius

	func print_self():
		var s: String = ""
		for n in neighbor:
			s = s + str(n.index) + "|"
		return (
			"(r:"
			+ str(level)
			+ " index: "
			+ str(index)
			+ ", neighbor: "
			+ str(s)
			+ " tag: "
			+ str(tag)
			+ " sub_array_size:"
			+ str(sub_array_size)
			+ " sub_index:"
			+ str(sub_index)
			+ " skip_tag:"
			+ str(skip_tag)
			+ ")"
		)
